using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

namespace OrigPacman
{
    public class Pacman
    {
        #region pacman data
        public enum Directions { NORTH, SOUTH, LEFT, RIGHT, STOP };
        //Various variables
        protected Texture2D pacmanUp;
        protected Texture2D pacmanDown;
        protected Texture2D pacmanRight;
        protected Texture2D pacmanLeft;
        protected Texture2D currentTexture;
        protected Texture2D deathFrames;
        protected Directions currentDirection;
        protected float spriteX = 0;
        protected float spriteY = 0;
        protected int currentX = 0;
        protected float totalTime = 0.0f;
        protected bool adjustDistance = false;
        //Values used when big pellet is eaten
        protected bool superMode = false;
        protected float superModeTime = 7.0f;
        //====================================
        protected List<Map.Waypoints> currentWaypoints = null;
        protected List<Ghost> currentGhostPositions = null;
        protected int nextWaypoint = 0;
        protected int prevWaypoint = 0;
        protected float length = 0.0f;
		protected int lives = 3;
		protected int score = 0;
        protected float frameTime = 0.25f;
        protected int currentDeathFrame = 0;
        protected bool playDeathAnimation = false;
        //Saves the current Key information
        protected Keys currentKey;
        //Used to log information
        protected bool death = false;


        public Texture2D PacmanUp
        {
            get { return pacmanUp; }
            set { pacmanUp = value; }
        }
        public Texture2D PacmanDown
        {
            get { return pacmanDown; }
            set { pacmanDown = value; }
        }
        public Texture2D PacmanRight
        {
            get { return pacmanRight; }
            set { pacmanRight = value; }
        }
        public Texture2D PacmanLeft
        {
            get { return pacmanLeft; }
            set { pacmanLeft = value; }
        }
        public Texture2D CurrentTexture
        {
            get { return currentTexture; }
            set { currentTexture = value; }
        }
        public Texture2D DeathFrames
        {
            get { return deathFrames; }
            set { deathFrames = value; }
        }
        public Directions CurrentDirection
        {
            get { return currentDirection; }
            set { currentDirection = value; }
        }
        public List<Map.Waypoints> CurrentWaypoints
        {
            get { return currentWaypoints; }
            set
            {
                currentWaypoints = value;
                if (currentWaypoints != null)
                {
                    Map.Waypoints tmp = (Map.Waypoints)value[0];
                    spriteX = tmp.Position.X;
                    spriteY = tmp.Position.Y;
                    nextWaypoint = tmp.Left;
                    prevWaypoint = tmp.Right;
                    currentDirection = Directions.LEFT;
                }
            }
        }
        public List<Ghost> CurrentGhostPositions
        {
            get { return currentGhostPositions; }
            set { currentGhostPositions = value; }
        }
        public Vector2 Position
        {
            get { return new Vector2(spriteX, spriteY); }
        }
        public bool Death
        {
            get { return death; }
        }
		public int Lives
		{
			get {return lives;}
			set { lives = value; }
		}
		public int Score
		{
			get {return score;}
			set { score = value; }
		}

        #endregion

        public Pacman()
        {

        }

        #region pacman methods
        public void UpdatePacman(float elapsed)
        {
            CheckKeys();
            death = false;
            if (!playDeathAnimation)
            {
                CheckCollisionWithGhosts();
                if (currentDirection == Directions.NORTH)
                {
                    spriteY -= 65.0f * elapsed;
                    currentTexture = pacmanUp;
                    if (adjustDistance)
                    {
                        spriteY -= length;
                        adjustDistance = false;
                    }

                }
                else if (currentDirection == Directions.SOUTH)
                {
                    spriteY += 65.0f * elapsed;
                    currentTexture = pacmanDown;
                    if (adjustDistance)
                    {
                        spriteY += length;
                        adjustDistance = false;
                    }
                }
                else if (currentDirection == Directions.LEFT)
                {

                    spriteX -= 65.0f * elapsed;
                    currentTexture = pacmanLeft;
                    if (adjustDistance)
                    {
                        spriteX -= length;
                        adjustDistance = false;
                    }

                }
                else if (currentDirection == Directions.RIGHT)
                {

                    spriteX += 65.0f * elapsed;
                    currentTexture = pacmanRight;
                    if (adjustDistance)
                    {
                        spriteX += length;
                        adjustDistance = false;
                    }

                }
                else if (currentDirection == Directions.STOP)
                {
                    //Do nothing
                    Map.Waypoints tmp = (Map.Waypoints)currentWaypoints[nextWaypoint];
                    spriteX = tmp.Position.X;
                    spriteY = tmp.Position.Y;
                }
                totalTime += elapsed;
                if (totalTime > 0.25f)
                {
                    currentKey = Keys.R;
                    currentX += 32;
                    totalTime = 0.0f;
                    if (currentX > 64)
                        currentX = 0;
                }
                CheckNextWaypoint();
            }
            else
            {
                //Update animation time
                frameTime -= elapsed;
            }


        }
        public void RenderPacman(ref SpriteBatch sprite)
        {
            if (!playDeathAnimation)
            {
                sprite.Draw(currentTexture, new Vector2(spriteX, spriteY), new Rectangle(currentX, 0, 32, 32), Color.White, 0.0f, new Vector2(16.0f, 16.0f), 1.0f, SpriteEffects.None, 0.1f);
            }
            else
            {
                //PlayAnimation
                if (frameTime < 0.0f && currentDeathFrame < 3)
                {
                    frameTime = 0.25f;
                    currentDeathFrame++;
                }

                sprite.Draw(deathFrames, new Vector2(spriteX, spriteY), new Rectangle(currentDeathFrame * 32, 0, 32, 32), Color.White, 0.0f, new Vector2(16.0f, 16.0f), 1.0f, SpriteEffects.None, 0.1f);
                if (currentDeathFrame == 3 && frameTime < 0.0f)
                {
                    frameTime = 0.25f;
                    currentDeathFrame = 0;
                    playDeathAnimation = false;
                    Map.Waypoints tmp = (Map.Waypoints)currentWaypoints[0];
                    spriteX = tmp.Position.X;
                    spriteY = tmp.Position.Y;
                    nextWaypoint = tmp.Left;
                    prevWaypoint = tmp.Right;
                    currentDirection = Directions.LEFT;

                }
            }


        }
        //Checks Key Presses when Pacman has not yet arrived to a junction
        private void CheckKeys()
        {
            if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Up) &&
                currentDirection == Directions.SOUTH)
            {
                int tmp = nextWaypoint;
                nextWaypoint = prevWaypoint;
                prevWaypoint = tmp;
                currentDirection = Directions.NORTH;
            }
            else if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Down) &&
                currentDirection == Directions.NORTH)
            {
                int tmp = nextWaypoint;
                nextWaypoint = prevWaypoint;
                prevWaypoint = tmp;
                currentDirection = Directions.SOUTH;
            }
            else if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Left) &&
                currentDirection == Directions.RIGHT)
            {
                int tmp = nextWaypoint;
                nextWaypoint = prevWaypoint;
                prevWaypoint = tmp;
                currentDirection = Directions.LEFT;
            }
            else if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Right) &&
                currentDirection == Directions.LEFT)
            {
                int tmp = nextWaypoint;
                nextWaypoint = prevWaypoint;
                prevWaypoint = tmp;
                currentDirection = Directions.RIGHT;
            }
            Keys tmpKey = currentKey;
            currentKey = getKeyPress();
            if (currentKey == Keys.R)
                currentKey = tmpKey;
        }
        private void CheckNextWaypoint()
        {
            Map.Waypoints tmp = (Map.Waypoints)currentWaypoints[nextWaypoint];
            Vector2 distance = (tmp.Position - new Vector2(spriteX, spriteY));
            length = distance.Length();
            if (getDirectionToWaypoint(distance) == currentDirection &&
                currentDirection != Directions.STOP)
            {
                adjustDistance = false;
                return;
            }
            else
            {
                adjustDistance = true;
                switch (currentKey)
                {
                    case Keys.Up:
                        if (tmp.Up < 90)
                        {

                            int way = nextWaypoint;
                            nextWaypoint = tmp.Up;
                            prevWaypoint = way;
                            currentDirection = Directions.NORTH;

                        }
                        else
                            currentDirection = Directions.STOP;
                        break;
                    case Keys.Down:
                        if (tmp.Down < 90)
                        {
                            int way = nextWaypoint;
                            nextWaypoint = tmp.Down;
                            prevWaypoint = way;
                            currentDirection = Directions.SOUTH;
                        }
                        else
                            currentDirection = Directions.STOP;
                        break;
                    case Keys.Left:
                        if (tmp.Left < 90)
                        {
                            int way = nextWaypoint;
                            nextWaypoint = tmp.Left;
                            prevWaypoint = way;
                            currentDirection = Directions.LEFT;
                        }
                        else
                            currentDirection = Directions.STOP;
                        break;
                    case Keys.Right:
                        if (tmp.Right < 90)
                        {
                            int way = nextWaypoint;
                            nextWaypoint = tmp.Right;
                            prevWaypoint = way;
                            currentDirection = Directions.RIGHT;
                        }
                        else
                            currentDirection = Directions.STOP;
                        break;
                    default:
                        switch (currentDirection)
                        {
                            case Directions.LEFT:
                                if (tmp.Left < 99)
                                {
                                    int way = nextWaypoint;
                                    nextWaypoint = tmp.Left;
                                    prevWaypoint = way;
                                }
                                else
                                    currentDirection = Directions.STOP;
                                break;
                            case Directions.NORTH:
                                if (tmp.Up < 99)
                                {
                                    int way = nextWaypoint;
                                    nextWaypoint = tmp.Up;
                                    prevWaypoint = way;
                                }
                                else
                                    currentDirection = Directions.STOP;
                                break;
                            case Directions.RIGHT:
                                if (tmp.Right < 99)
                                {
                                    int way = nextWaypoint;
                                    nextWaypoint = tmp.Right;
                                    prevWaypoint = way;
                                }
                                else
                                    currentDirection = Directions.STOP;
                                break;
                            case Directions.SOUTH:
                                if (tmp.Down < 99)
                                {
                                    int way = nextWaypoint;
                                    nextWaypoint = tmp.Down;
                                    prevWaypoint = way;
                                }
                                else
                                    currentDirection = Directions.STOP;
                                break;
                        }//End Switch
                        break;
                }//End switch;
            }
        }
        private Keys getKeyPress()
        {
            if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Up))
                return Keys.Up;
            if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Down))
                return Keys.Down;
            if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Left))
                return Keys.Left;
            if (KeyPress.KeyPressGame.KeyPressedThisFrame(Keys.Right))
                return Keys.Right;
            return Keys.R;
        }
        private Directions getDirectionToWaypoint(Vector2 vec)
        {
            vec.Normalize();
            if (vec.X < 0.45f && vec.X > -0.45f)
            {
                vec.X = 0.0f;
            }
            if (vec.X < -0.5f)
            {
                vec.X = -1.0f;
                vec.Y = 0.0f;
            }
            if (vec.X > 0.5)
            {
                vec.X = 1.0f;
                vec.Y = 0.0f;
            }
            if (vec.Y < 0.45f && vec.Y > -0.45f)
            {
                vec.Y = 0.0f;
            }
            if (vec.Y > 0.5)
            {
                vec.Y = 1.0f;
                vec.X = 0.0f;
            }
            if (vec.Y < -0.5f)
            {
                vec.Y = -1.0f;
                vec.X = 0.0f;
            }
            if (vec.X == 1.0f)
                return Directions.RIGHT;
            else if (vec.X == -1.0f)
                return Directions.LEFT;
            else if (vec.Y == 1.0f)
                return Directions.SOUTH;
            else if (vec.Y == -1.0f)
                return Directions.NORTH;
            return Directions.STOP;
        }
        private void CheckCollisionWithGhosts()
        {
            if (currentGhostPositions != null)
            {
                foreach (Ghost a in currentGhostPositions)
                {
                    //Calculate the distance to the ghost
                    Vector2 distance = a.Position - new Vector2(spriteX, spriteY);
                    if (distance.Length() < 32)
                    {
                        //Collision
                        playDeathAnimation = true;
                        death = true;
                        lives--;
                        break;
                    }
                }//End for each
            }//End if
        }//End function CheckCollisionWithGhosts
        #endregion


    }
}
